﻿using IOP.Extension.DependencyInjection;
using IOP.ISEA;
using IOP.SgrA;
using IOP.SgrA.SilkNet.Vulkan;
using Silk.NET.Vulkan;
using System;
using System.IO;
using System.Numerics;
using System.Threading.Tasks;

namespace VkSample47
{
    public class WindowModule : VulkanModule, IVulkanRenderWapperModule
    {
        public VulkanRenderWapper RenderWapper { get; set; }

        protected override async Task Load(VulkanGraphicsManager manager)
        {
            var lDevice = manager.VulkanDevice;
            var pipeCache = lDevice.PipelineCache;
            var dispatcher = RenderWapper.GetRenderDispatcher<VulkanSwapchainRenderDispatcher>();
            var pass = dispatcher.GetSwapchainRenderPass();
            var area = RenderWapper.RenderArea;

            VulkanShaderInfo[] infos = new VulkanSPVShaderInfo[]
            {
                new VulkanSPVShaderInfo(ShaderTypes.VertexShader, "main_vert", new FileInfo(Path.Combine("shaders","vert.spv"))),
                new VulkanSPVShaderInfo(ShaderTypes.FragmentShader, "main_frag", new FileInfo(Path.Combine("shaders","frag.spv")))
            };
            manager.LoadShaders(infos);
            VulkanPipeline[] pipelines = new VulkanPipeline[3];
            var command = lDevice.CreateCommandPool((device, option) =>
            {
                option.Flags = CommandPoolCreateFlags.CommandPoolCreateResetCommandBufferBit;
                option.QueueFamilyIndex = device.WorkQueues[0].FamilyIndex;
            }).CreatePrimaryCommandBuffer();
            var sCommands = lDevice.CreateCommandPool((device, option) =>
            {
                option.Flags = CommandPoolCreateFlags.CommandPoolCreateResetCommandBufferBit;
                option.QueueFamilyIndex = device.WorkQueues[0].FamilyIndex;
            }).CreateCommandBuffers(CommandBufferLevel.Secondary, 3);
            for (int i = 0; i < pipelines.Length; i++)
            {
                pipelines[i] = manager.CreateEmptyPipeline($"MainPipline{i}")
                    .BuildPipelineLayoutFromConfiguration("DescriptorSetLayoutCreateOptions", null)
                    .BuildUniformBuffer(0, 0, sizeof(float) * 16, SharingMode.Exclusive)
                    .BuildGraphicsPipelineFromConfiguration(pass, pipeCache, infos, $"Pipeline{i}");
            }
            manager.DeleteShaders(infos);

            var fence = lDevice.CreateFence();
            var group = manager.CreatePrimaryRenderGroup("MainRenderGroup", null)
            .Binding(command, lDevice, pass, new Semaphore[] { dispatcher.ImageAvailableSemaphore, dispatcher.RenderFinishSemaphore }, new Fence[] { fence.RawHandle });
            group.CreateGroupRenderingAction((builder) => builder.UseMiddleware<MainGroupRenderingMiddleware>());

            var aspect = area.Width / (float)(area.Height);
            var camera = new Camera(new Vector3(0, 0, 200), new Vector3(0, 0, 0), new Vector3(0, 1, 0));
            camera.SetProjectMatrix(-aspect, 1.0f, 1.5f, 1000);

            ISEADocument document = new ISEADocument();
            await document.Load(Path.Combine(AppContext.BaseDirectory, "Test47.isea"));
            var renders = await manager.CreateRenderObjectsFromISEA<RenderObject>(document);
            var archetype = ContextManager.CreateArchetype(new TransformComponent());

            for (int i = 0; i < pipelines.Length; i++)
            {
                var item = manager.CreateSecondaryVulkanRenderGroup($"SGroup{i}", pipelines[i])
                .Binding(group, sCommands[i], new VulkanSemaphore[0], new VulkanFence[0]);
                item.SetCamera(camera);
                item.CreateGroupRenderingAction((builder) => builder.UseMiddleware<SecondaryRenderingMiddleware>());
                item.CreateItemRenderingAction((builder) => builder.UseMiddleware<GroupItemMiddleware>());
                ContextManager.CreateContexts(1, archetype, item, renders[0]);
                if (i != 0) item.Disable();
            }

            RenderWapper.CreateAndCutScene<Scene>("Main", group, typeof(InputSystem));
        }

        protected override Task Unload(VulkanGraphicsManager manager)
        {
            return Task.CompletedTask;
        }
    }
}
